﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace spline {

    class Spline {
        double a;
        double b;
        int N;
        String function;
        int NN;

        private List<double> segments;
        private List<double> solutions;

        public Spline(double a, double b, int n, int nn, String f){
            this.a = a;
            this.b = b;
            N = n;
            NN = nn;
            function = f;
            solutions = new List<double>();
        }

        public void makeSegments() {
            segments = new List<double>();
            double width = b - a;
            double segm = width / N;
            double tmp = a;
            while (tmp < b) {
                segments.Add(tmp);
                tmp += segm;
            }
            if (segments[segments.Count - 1] != b) {
                segments.Add(b);
            }
            
        }

        public void makeSolution() {
            makeSegments();
            for (int i = 0; i < segments.Count - 1; i++) {
                addSolutionsFromSegment(segments[i], segments[i + 1]);
            }
        }

        public List<double> getSolution() {
            return solutions;
        }

        private void addSolutionsFromSegment(double x1, double x2) {
            double a0, a1, a2, a3, A0, A1, A2, A3;
            bool flag = false;
            double y1 = Functions.f(function, x1);
            double y2 = Functions.f(function, x2);
            double y1d = Functions.derivate(function, x1);
            double y2d = Functions.derivate(function, x2);
            a0 = y1;
            a1 = y1d;
            double h = x2 - x1; 
            double b2 = (y2d - y1d) / h;
            double b1 = (y2 - y1d * h - y1) / (h * h);
            a3 = b2 - 2 * b1;
            a2 = b1 - a3 * h;

            A3 = a3;

            A2 = -3 * a3 * x1 + a2;

            A1 = 3 * x1 * x1 * a3 + a1 - 2* x1 * a2;

            A0 = a0 - a3 * x1 * x1 * x1 + x1 * x1 * a2 - a1* x1; 
 
            double s1, s2, s3;
            s1 = s2 = s3 = Double.NaN;
            if (a3 == 0 && a2 == 0) {
                s1 = Functions.first_pow(A1, A0);
            }
            else if (a3 == 0) {
                Functions.second_pow(A2, A1, A0, out s1, out s2);
            }
            else {
                Functions.third_pow(A3, A2, A1, A0, out s1, out s2, out s3);
            }

            if (!Double.IsNaN(s1) && s1 <= x2 && s1 > x1) {  flag = true; }
            if (!Double.IsNaN(s2) && s2 <= x2 && s2 > x1) {  flag = true; }
            if (!Double.IsNaN(s3) && s3 <= x2 && s3 > x1) {  flag = true; }
            if(flag) solutions.Add(Newton.Solve(function,x1,x2,0.00000001));
        }
    }
}
